export default {
    props: {
        localdata: {
            type: [Array, Object],
            default() {
                return [];
            }
        },
        spaceInfo: {
            type: Object,
            default() {
                return {};
            }
        },
        collection: {
            type: String,
            default: ""
        },
        action: {
            type: String,
            default: ""
        },
        field: {
            type: String,
            default: ""
        },
        orderby: {
            type: String,
            default: ""
        },
        where: {
            type: [String, Object],
            default: ""
        },
        pageData: {
            type: String,
            default: "add"
        },
        pageCurrent: {
            type: Number,
            default: 1
        },
        pageSize: {
            type: Number,
            default: 500
        },
        getcount: {
            type: [Boolean, String],
            default: false
        },
        getone: {
            type: [Boolean, String],
            default: false
        },
        gettree: {
            type: [Boolean, String],
            default: false
        },
        manual: {
            type: Boolean,
            default: false
        },
        value: {
            type: [Array, String, Number],
            default() {
                return [];
            }
        },
        modelValue: {
            type: [Array, String, Number],
            default() {
                return [];
            }
        },
        preload: {
            type: Boolean,
            default: false
        },
        stepSearh: {
            type: Boolean,
            default: true
        },
        selfField: {
            type: String,
            default: ""
        },
        parentField: {
            type: String,
            default: ""
        },
        multiple: {
            type: Boolean,
            default: false
        },
        map: {
            type: Object,
            default() {
                return {
                    text: "text",
                    value: "value"
                };
            }
        }
    },
    data() {
        return {
            loading: false,
            errorMessage: "",
            loadMore: {
                contentdown: "",
                contentrefresh: "",
                contentnomore: ""
            },
            dataList: [],
            selected: [],
            selectedIndex: 0,
            page: {
                current: this.pageCurrent,
                size: this.pageSize,
                count: 0
            }
        };
    },
    computed: {
        isLocalData() {
            return !this.collection.length;
        },
        isCloudData() {
            return this.collection.length > 0;
        },
        isCloudDataList() {
            return this.isCloudData && !this.parentField && !this.selfField;
        },
        isCloudDataTree() {
            return this.isCloudData && this.parentField && this.selfField;
        },
        dataValue() {
            let isModelValue = Array.isArray(this.modelValue)
                ? this.modelValue.length > 0
                : this.modelValue !== null || this.modelValue !== undefined;
            return isModelValue ? this.modelValue : this.value;
        },
        hasValue() {
            if (typeof this.dataValue === "number") {
                return true;
            }
            return this.dataValue != null && this.dataValue.length > 0;
        }
    },
    created() {
        this.$watch(
            () => {
                var al = [];
                [
                    "pageCurrent",
                    "pageSize",
                    "spaceInfo",
                    "value",
                    "modelValue",
                    "localdata",
                    "collection",
                    "action",
                    "field",
                    "orderby",
                    "where",
                    "getont",
                    "getcount",
                    "gettree"
                ].forEach((key) => {
                    al.push(this[key]);
                });
                return al;
            },
            (newValue, oldValue) => {
                let needReset = false;
                for (let i = 2; i < newValue.length; i++) {
                    if (newValue[i] != oldValue[i]) {
                        needReset = true;
                        break;
                    }
                }
                if (newValue[0] != oldValue[0]) {
                    this.page.current = this.pageCurrent;
                }
                this.page.size = this.pageSize;

                this.onPropsChange();
            }
        );
        this._treeData = [];
    },
    methods: {
        onPropsChange() {
            this._treeData = [];
        },

        // 填充 pickview 数据
        async loadData() {
            if (this.isLocalData) {
                this.loadLocalData();
            } else if (this.isCloudDataList) {
                this.loadCloudDataList();
            } else if (this.isCloudDataTree) {
                this.loadCloudDataTree();
            }
        },

        // 加载本地数据
        async loadLocalData() {
            this._treeData = [];
            this._extractTree(this.localdata, this._treeData);

            let inputValue = this.dataValue;
            if (inputValue === undefined) {
                return;
            }

            if (Array.isArray(inputValue)) {
                inputValue = inputValue[inputValue.length - 1];
                if (typeof inputValue === "object" && inputValue[this.map.value]) {
                    inputValue = inputValue[this.map.value];
                }
            }

            this.selected = this._findNodePath(inputValue, this.localdata);
        },

        // 加载 Cloud 数据 (单列)
        async loadCloudDataList() {
            if (this.loading) {
                return;
            }
            this.loading = true;

            try {
                let response = await this.getCommand();
                let responseData = response.result.data;

                this._treeData = responseData;

                this._updateBindData();
                this._updateSelected();

                this.onDataChange();
            } catch (e) {
                this.errorMessage = e;
            } finally {
                this.loading = false;
            }
        },

        // 加载 Cloud 数据 (树形)
        async loadCloudDataTree() {
            if (this.loading) {
                return;
            }
            this.loading = true;

            try {
                let commandOptions = {
                    field: this._cloudDataPostField(),
                    where: this._cloudDataTreeWhere()
                };
                if (this.gettree) {
                    commandOptions.startwith = `${this.selfField}=='${this.dataValue}'`;
                }

                let response = await this.getCommand(commandOptions);
                let responseData = response.result.data;

                this._treeData = responseData;
                this._updateBindData();
                this._updateSelected();

                this.onDataChange();
            } catch (e) {
                this.errorMessage = e;
            } finally {
                this.loading = false;
            }
        },

        // 加载 Cloud 数据 (节点)
        async loadCloudDataNode(callback) {
            if (this.loading) {
                return;
            }
            this.loading = true;

            try {
                let commandOptions = {
                    field: this._cloudDataPostField(),
                    where: this._cloudDataNodeWhere()
                };

                let response = await this.getCommand(commandOptions);
                let responseData = response.result.data;

                callback(responseData);
            } catch (e) {
                this.errorMessage = e;
            } finally {
                this.loading = false;
            }
        },

        // 回显 Cloud 数据
        getCloudDataValue() {
            if (this.isCloudDataList) {
                return this.getCloudDataListValue();
            }

            if (this.isCloudDataTree) {
                return this.getCloudDataTreeValue();
            }
        },

        // 回显 Cloud 数据 (单列)
        getCloudDataListValue() {
            // 根据 field's as value标识匹配 where 条件
            let where = [];
            let whereField = this._getForeignKeyByField();
            if (whereField) {
                where.push(`${whereField} == '${this.dataValue}'`);
            }

            where = where.join(" || ");

            if (this.where) {
                where = `(${this.where}) && (${where})`;
            }

            return this.getCommand({
                field: this._cloudDataPostField(),
                where
            }).then((res) => {
                this.selected = res.result.data;
                return res.result.data;
            });
        },

        // 回显 Cloud 数据 (树形)
        getCloudDataTreeValue() {
            return this.getCommand({
                field: this._cloudDataPostField(),
                getTreePath: {
                    startWith: `${this.selfField}=='${this.dataValue}'`
                }
            }).then((res) => {
                let treePath = [];
                this._extractTreePath(res.result.data, treePath);
                this.selected = treePath;
                return treePath;
            });
        },

        getCommand(options = {}) {
            /* eslint-disable no-undef */
            let db = uniCloud.database(this.spaceInfo);

            const action = options.action || this.action;
            if (action) {
                db = db.action(action);
            }

            const collection = options.collection || this.collection;
            db = db.collection(collection);

            const where = options.where || this.where;
            if (!(!where || !Object.keys(where).length)) {
                db = db.where(where);
            }

            const field = options.field || this.field;
            if (field) {
                db = db.field(field);
            }

            const orderby = options.orderby || this.orderby;
            if (orderby) {
                db = db.orderBy(orderby);
            }

            const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current;
            const size = options.pageSize !== undefined ? options.pageSize : this.page.size;
            const getCount = options.getcount !== undefined ? options.getcount : this.getcount;
            const getTree = options.gettree !== undefined ? options.gettree : this.gettree;

            const getOptions = {
                getCount,
                getTree
            };
            if (options.getTreePath) {
                getOptions.getTreePath = options.getTreePath;
            }

            db = db
                .skip(size * (current - 1))
                .limit(size)
                .get(getOptions);

            return db;
        },

        _cloudDataPostField() {
            let fields = [this.field];
            if (this.parentField) {
                fields.push(`${this.parentField} as parent_value`);
            }
            return fields.join(",");
        },

        _cloudDataTreeWhere() {
            let result = [];
            let selected = this.selected;
            let parentField = this.parentField;
            if (parentField) {
                result.push(`${parentField} == null || ${parentField} == ""`);
            }
            if (selected.length) {
                for (var i = 0; i < selected.length - 1; i++) {
                    result.push(`${parentField} == '${selected[i].value}'`);
                }
            }

            let where = [];
            if (this.where) {
                where.push(`(${this.where})`);
            }

            if (result.length) {
                where.push(`(${result.join(" || ")})`);
            }

            return where.join(" && ");
        },

        _cloudDataNodeWhere() {
            let where = [];
            let selected = this.selected;
            if (selected.length) {
                where.push(`${this.parentField} == '${selected[selected.length - 1].value}'`);
            }

            where = where.join(" || ");

            if (this.where) {
                return `(${this.where}) && (${where})`;
            }

            return where;
        },

        _getWhereByForeignKey() {
            let result = [];
            let whereField = this._getForeignKeyByField();
            if (whereField) {
                result.push(`${whereField} == '${this.dataValue}'`);
            }

            if (this.where) {
                return `(${this.where}) && (${result.join(" || ")})`;
            }

            return result.join(" || ");
        },

        _getForeignKeyByField() {
            let fields = this.field.split(",");
            let whereField = null;
            for (let i = 0; i < fields.length; i++) {
                const items = fields[i].split("as");
                if (items.length < 2) {
                    continue;
                }
                if (items[1].trim() === "value") {
                    whereField = items[0].trim();
                    break;
                }
            }
            return whereField;
        },

        _updateBindData(node) {
            const { dataList, hasNodes } = this._filterData(this._treeData, this.selected);

            let isleaf = this._stepSearh === false && !hasNodes;

            if (node) {
                node.isleaf = isleaf;
            }

            this.dataList = dataList;
            this.selectedIndex = dataList.length - 1;

            if (!isleaf && this.selected.length < dataList.length) {
                this.selected.push({
                    value: null,
                    text: "请选择"
                });
            }

            return {
                isleaf,
                hasNodes
            };
        },

        _updateSelected() {
            let dl = this.dataList;
            let sl = this.selected;
            let textField = this.map.text;
            let valueField = this.map.value;
            for (let i = 0; i < sl.length; i++) {
                let value = sl[i].value;
                let dl2 = dl[i];
                for (let j = 0; j < dl2.length; j++) {
                    let item2 = dl2[j];
                    if (item2[valueField] === value) {
                        sl[i].text = item2[textField];
                        break;
                    }
                }
            }
        },

        _filterData(data, paths) {
            let dataList = [];
            let hasNodes = true;

            dataList.push(
                data.filter((item) => {
                    return item.parent_value === null || item.parent_value === undefined || item.parent_value === "";
                })
            );
            for (let i = 0; i < paths.length; i++) {
                let value = paths[i].value;
                let nodes = data.filter((item) => {
                    return item.parent_value === value;
                });

                if (nodes.length) {
                    dataList.push(nodes);
                } else {
                    hasNodes = false;
                }
            }

            return {
                dataList,
                hasNodes
            };
        },

        _extractTree(nodes, result, parent_value) {
            let list = result || [];
            let valueField = this.map.value;
            for (let i = 0; i < nodes.length; i++) {
                let node = nodes[i];

                let child = {};
                for (let key in node) {
                    if (key !== "children") {
                        child[key] = node[key];
                    }
                }
                if (parent_value !== null && parent_value !== undefined && parent_value !== "") {
                    child.parent_value = parent_value;
                }
                result.push(child);

                let children = node.children;
                if (children) {
                    this._extractTree(children, result, node[valueField]);
                }
            }
        },

        _extractTreePath(nodes, result) {
            let list = result || [];
            for (let i = 0; i < nodes.length; i++) {
                let node = nodes[i];

                let child = {};
                for (let key in node) {
                    if (key !== "children") {
                        child[key] = node[key];
                    }
                }
                result.push(child);

                let children = node.children;
                if (children) {
                    this._extractTreePath(children, result);
                }
            }
        },

        _findNodePath(key, nodes, path = []) {
            let textField = this.map.text;
            let valueField = this.map.value;
            for (let i = 0; i < nodes.length; i++) {
                let node = nodes[i];
                let children = node.children;
                let text = node[textField];
                let value = node[valueField];

                path.push({
                    value,
                    text
                });

                if (value === key) {
                    return path;
                }

                if (children) {
                    const p = this._findNodePath(key, children, path);
                    if (p.length) {
                        return p;
                    }
                }

                path.pop();
            }
            return [];
        }
    }
};
